package org.budo.support.freemarker;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Map;

import org.budo.support.lang.util.IoUtil;
import org.budo.support.lang.util.MapUtil;
import org.budo.support.lang.util.UuidUtil;

import freemarker.cache.StringTemplateLoader;
import freemarker.ext.beans.BeansWrapper;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateHashModel;

/**
 * @author limingwei2
 */
public class FreemarkerUtil {
    private static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

    private static final String HH_MM_SS = "HH:mm:ss";

    private static final String YYYY_MM_DD = "yyyy-MM-dd";

    private static final String UTF_8 = "UTF-8";

    public static Template buildTemplate(InputStream inputStream) {
        String template = IoUtil.toString(inputStream, UTF_8);
        return buildTemplate(template);
    }

    public static Template buildTemplate(String templateInput) {
        try {
            @SuppressWarnings("deprecation")
            Configuration configuration = new Configuration(); // 兼容低版本 freemarker

            configuration.setDefaultEncoding(UTF_8);
            configuration.setDateFormat(YYYY_MM_DD);
            configuration.setTimeFormat(HH_MM_SS);
            configuration.setDateTimeFormat(YYYY_MM_DD_HH_MM_SS);

            StringTemplateLoader templateLoader = new StringTemplateLoader();
            String templateName = UuidUtil.randomUuid(); // templateName
            templateLoader.putTemplate(templateName, templateInput);

            configuration.setTemplateLoader(templateLoader);

            return configuration.getTemplate(templateName);
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }

    @SuppressWarnings("deprecation")
    public static void freemarkerRender(Template freemarkerTemplate, Object dataMap, OutputStream outputStream) {
        try {
            if (null == dataMap) {
                dataMap = MapUtil.stringObjectMap();
            }

            if (dataMap instanceof Map) {
                TemplateHashModel staticModels = BeansWrapper.getDefaultInstance().getStaticModels();
                ((Map) dataMap).put("def", staticModels);
            }

            OutputStreamWriter writer = new OutputStreamWriter(outputStream);
            freemarkerTemplate.process(dataMap, writer);
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }

    public static String freemarkerRender(InputStream templateInputStream, Object dataMap) {
        Template template = buildTemplate(templateInputStream);
        return freemarkerRender(template, dataMap);
    }

    public static String freemarkerRender(Template freemarkerTemplate, Object dataMap) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        freemarkerRender(freemarkerTemplate, dataMap, byteArrayOutputStream);
        return new String(byteArrayOutputStream.toByteArray());
    }

    public static void freemarkerRender(String templateInput, Object dataMap, OutputStream outputStream) {
        Template freemarkerTemplate = buildTemplate(templateInput);
        freemarkerRender(freemarkerTemplate, dataMap, outputStream);
    }

    public static void freemarkerRender(InputStream templateInputStream, Object dataMap, File file) {
        freemarkerRender(templateInputStream, dataMap, IoUtil.fileOutputStream(file));
    }

    public static String freemarkerRender(String templateInput, Object dataMap) {
        Template freemarkerTemplate = buildTemplate(templateInput);
        return freemarkerRender(freemarkerTemplate, dataMap);
    }

    public static void freemarkerRender(InputStream templateInputStream, Object dataMap, OutputStream outputStream) {
        Template freemarkerTemplate = buildTemplate(templateInputStream);
        freemarkerRender(freemarkerTemplate, dataMap, outputStream);
    }
}